/*
 * Copyright (C) 2001-2006 the xine-project
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
 * USA
 *
 * $Id: wizards.c,v 1.46 2006-03-08 23:42:21 dsalt Exp $
 *
 * stuff to run on first startup / setup wizards
 */

#include "globals.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

#include <X11/Xlib.h>

#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <glib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "wizards.h"
#include "ui.h"
#include "utils.h"
#include "desktop_integration.h"
#include "preferences.h"

static GtkWidget *add_label (GtkWidget *vbox, const char *label)
{
  GtkWidget *l = gtk_label_new (label);
  gtk_label_set_line_wrap (GTK_LABEL (l), TRUE);
  gtk_label_set_use_markup (GTK_LABEL (l), TRUE);
  gtk_misc_set_alignment (GTK_MISC (l), 0, 0.5);
  gtk_box_pack_start (GTK_BOX(vbox), l, FALSE, FALSE, 5);
  return l;
}

static GtkWidget *add_heading (GtkWidget *vbox, const char *label)
{
  char *markup = g_strdup_printf ("<big><b>%s</b></big>", label);
  GtkWidget *l = add_label (vbox, markup);
  free (markup);
  return l;
}

static gboolean do_welcome (GtkWidget *dlg, GtkWidget *vbox)
{
  add_heading (vbox, _("Welcome to gxine!\n\n"));
  add_label (vbox, _("Would you like to run some setup wizards now "
		     "that will check your installation and maybe "
		     "do some adjustments for you if necessary?\n\n"
		     "If you do not want to run the wizards right now, "
		     "just click on the <i>Close</i> button and you will "
		     "not be bothered again.\n\n"
		     "You can always run the wizards (again) from the "
		     "help menu."));
  return FALSE;
};


typedef struct {
  char *msg, *explanation;
} hc_msg_t;

static void details_cb (GtkWidget* widget, gpointer data)
{
  hc_msg_t *msg = data;
  display_info (FROM_GXINE, _("Health Check Results"), "%s\n%s",
		msg->msg, msg->explanation);
}

static void hc_update_pref (const char *pref, const char *value)
{
  xine_cfg_entry_t entry;
  xine_config_lookup_entry (xine, pref, &entry);
  entry.str_value = (char *)value;
  preferences_update_entry (&entry);
}

static gboolean do_health_check (GtkWidget *dlg, GtkWidget *vbox)
{
  GtkWidget           *l, *table, *b;
  xine_health_check_t  hc;
  xine_health_check_t *results;
  int                  check;
  hc_msg_t            *msg;

  table = gtk_table_new (1, 1, FALSE);

  add_heading (vbox, _("System configuration check"));
  add_label (vbox, _("The xine engine runs certain checks on your "
		     "system configuration. Results follow:"));

  /* If media.vcd.device is empty, set it to the default "/dev/cdrom" */
  hc.cdrom_dev = xine_config_register_string(xine,
      "media.vcd.device",
      "/dev/cdrom",
      _("device used for CD-ROM drive"),
      NULL, 0, NULL, NULL);

  /* Similarly for media.audio_cd.device */
  const char *audio_cd = xine_config_register_string(xine,
      "media.audio_cd.device",
      "/dev/cdrom",
      _("device used for CD-ROM drive"),
      NULL, 0, NULL, NULL);

  if (!audio_cd || !*audio_cd)
    audio_cd = hc.cdrom_dev;
  if (!audio_cd || !*audio_cd)
    audio_cd = "/dev/cdrom";
  if (!hc.cdrom_dev || !*hc.cdrom_dev)
    hc.cdrom_dev = audio_cd;

  /* If media.dvd.device is empty, set it to the default "/dev/dvd" */
  hc.dvd_dev = xine_config_register_string(xine,
      "media.dvd.device",
      "/dev/dvd",
      _("device used for DVD drive"),
      NULL, 0, NULL, NULL);

  if (!hc.dvd_dev || !*hc.dvd_dev)
    hc.dvd_dev = "/dev/dvd";

  hc_update_pref ("media.audio_cd.device", audio_cd);
  hc_update_pref ("media.vcd.device", hc.cdrom_dev);
  hc_update_pref ("media.dvd.device", hc.dvd_dev);

  /* Run tests */
  for (check = 0; ; ++check)
  {
    results = xine_health_check (&hc, check);

    if (results->status == XINE_HEALTH_CHECK_NO_SUCH_CHECK)
      break;

    gtk_table_resize (GTK_TABLE (table), 3, check+1);

    l = gtk_label_new (results->title);
    gtk_table_attach (GTK_TABLE (table), l, 0, 1, check, check+1, GTK_FILL,
		      GTK_SHRINK, 2, 5);
    gtk_misc_set_alignment (GTK_MISC (l), 0, 0.5);

    switch (results->status)
    {
    case XINE_HEALTH_CHECK_UNSUPPORTED:
    case XINE_HEALTH_CHECK_OK:
      l = gtk_image_new_from_stock (GTK_STOCK_YES, GTK_ICON_SIZE_BUTTON);
      break;
    case XINE_HEALTH_CHECK_FAIL:
      msg = malloc (sizeof (hc_msg_t));

      msg->msg = results->msg;
      msg->explanation = results->explanation;

      b = gtk_button_new_with_label (_("Details"));
      g_signal_connect (G_OBJECT (b), "clicked", G_CALLBACK (details_cb), msg);
      gtk_table_attach (GTK_TABLE (table), b, 2, 3, check, check+1, GTK_FILL,
			GTK_SHRINK, 2, 5);

      l = gtk_image_new_from_stock (GTK_STOCK_NO, GTK_ICON_SIZE_BUTTON);
      break;
    }

    gtk_table_attach (GTK_TABLE (table), l, 1, 2, check, check+1, GTK_FILL,
		      GTK_SHRINK, 2, 5);
  }

  gtk_box_pack_start (GTK_BOX(vbox), table, FALSE, FALSE, 5);
  return FALSE;
}

#ifdef USE_INTEGRATION_WIZARD
static GtkWidget *cb_moz;
static GtkWidget *cb_gnome;
static GtkWidget *cb_kde;
static GtkWidget *cb_mailcap;

static void integrate_cb (GtkButton *button, gpointer data)
{
  gboolean state = !!data;
  if (GTK_WIDGET_SENSITIVE (cb_mailcap))
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cb_mailcap), state);
  if (GTK_WIDGET_SENSITIVE (cb_moz))
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cb_moz), state);
  if (GTK_WIDGET_SENSITIVE (cb_gnome))
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cb_gnome), state);
  if (GTK_WIDGET_SENSITIVE (cb_kde))
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cb_kde), state);
}

static gboolean ask_integration_wizard (GtkWidget *w, GtkWidget *vbox)
{
  struct stat st;
  gchar *sname;
  GtkWidget *b, *hbox;
  gboolean enable;

  add_heading (vbox, _("Registration"));
  add_label (vbox, _("Register gxine with the following applications "
		     "as a media handler/helper:"));

  cb_mailcap = gtk_check_button_new_with_mnemonic ("~_/.mailcap");
  gtk_box_pack_start (GTK_BOX(vbox), cb_mailcap, FALSE, FALSE, 5);
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cb_mailcap), TRUE);

  cb_moz = gtk_check_button_new_with_mnemonic (_("_Mozilla & Mozilla Firefox (plugin)"));
  gtk_box_pack_start (GTK_BOX(vbox), cb_moz, FALSE, FALSE, 5);
  sname = g_build_filename (plugindir, "gxineplugin.so", NULL);
  enable = !stat (sname, &st);
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cb_moz), enable);
  gtk_widget_set_sensitive (cb_moz, enable);
  g_free (sname);

  cb_gnome = gtk_check_button_new_with_mnemonic (_("_GNOME, Nautilus"));
  gtk_box_pack_start (GTK_BOX(vbox), cb_gnome, FALSE, FALSE, 5);
  enable = di_gnome_vfs_init ();
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cb_gnome), enable);
  gtk_widget_set_sensitive (cb_gnome, enable);

  cb_kde = gtk_check_button_new_with_mnemonic (_("_KDE, Konqueror"));
  gtk_box_pack_start (GTK_BOX(vbox), cb_kde, FALSE, FALSE, 5);
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cb_kde), TRUE);

  hbox = gtk_hbox_new (FALSE, 2);
  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2);

  b = ui_button_new_stock_mnemonic (GTK_STOCK_ADD, _("_All"));
  gtk_box_pack_start (GTK_BOX (hbox), b, FALSE, FALSE, 2);
  g_signal_connect (G_OBJECT (b), "clicked",
		    (GCallback) integrate_cb, integrate_cb);

  b = ui_button_new_stock_mnemonic (GTK_STOCK_REMOVE, _("_None"));
  gtk_box_pack_start (GTK_BOX (hbox), b, FALSE, FALSE, 2);
  g_signal_connect (G_OBJECT (b), "clicked",
		    (GCallback) integrate_cb, NULL);

  return FALSE;
}

static void desktop_integration (void)
{
  di_registration_flush ();
  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (cb_mailcap)))
    di_register_mailcap();
  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (cb_gnome)))
    di_register_gnome();
  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (cb_kde)))
    di_register_kde();
  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (cb_moz)))
    di_register_mozilla();
}

static gboolean report_integration_wizard (GtkWidget *w, GtkWidget *vbox)
{
  const char *report = di_registration_report ();
  if (!report)
    return TRUE;

  add_heading (vbox, _("Registration report"));
  add_label (vbox, _("There were some problems during registration."));
  add_label (vbox, report);
  di_registration_flush ();

  return FALSE;
}
#endif

#define RESPONSE_CLOSE 0
#define RESPONSE_NEXT  1

static gboolean close_cb (GtkWidget* widget, gpointer data)
{
  int *b = data;
  *b = RESPONSE_CLOSE;
  gtk_main_quit();

  return TRUE;
}

static void response_cb (GtkDialog *dbox, int response, gpointer data)
{
  int *b = data;
  switch (response)
  {
  case GTK_RESPONSE_ACCEPT:
    *b = RESPONSE_NEXT;
    break;
  default:
    *b = RESPONSE_CLOSE;
  }
  gtk_main_quit();
}

#define WIZARDS_LEVEL 6

void run_wizards (gboolean requested)
{
  static GtkWidget *dlg = NULL;

  if (dlg)
  {
    gtk_window_set_modal (GTK_WINDOW (dlg), FALSE);
    gtk_window_present (GTK_WINDOW(dlg));
    return;
  }

  if (requested
      || (xine_config_register_num (xine, "misc.wizards_shown", 0,
				    _("Keep track of whether user has seen wizards yet"),
				    NULL, 20, NULL, NULL) < WIZARDS_LEVEL))
  {
    xine_cfg_entry_t  entry;
    int b, state;

    static const struct {
      GtkWidget *(*create) (GtkWidget *, GtkWidget *);
      gboolean (*action) (void); /* TRUE to skip a stage */
    } wizards[] = {
      { do_welcome, NULL },
      { do_health_check, NULL },
#ifdef USE_INTEGRATION_WIZARD
      { ask_integration_wizard, desktop_integration },
      { report_integration_wizard, NULL },
#endif
      { NULL }
    };

    if (xine_config_lookup_entry (xine, "misc.wizards_shown", &entry))
    {
      entry.num_value = WIZARDS_LEVEL;
      preferences_update_entry (&entry);
    }

    /* set up dialog which all wizards will use */

    dlg = gtk_dialog_new_with_buttons (_("gxine setup wizards"), NULL, 0,
				       GTK_STOCK_GO_FORWARD, GTK_RESPONSE_ACCEPT,
				       GTK_STOCK_CLOSE, GTK_RESPONSE_DELETE_EVENT,
				       NULL);
    gtk_dialog_set_default_response (GTK_DIALOG(dlg), GTK_RESPONSE_ACCEPT);
    gtk_window_set_default_size (GTK_WINDOW (dlg), -1, 400);
    gtk_window_set_modal (GTK_WINDOW (dlg), !requested);
    g_object_connect (G_OBJECT (dlg),
	"signal::delete-event", G_CALLBACK (close_cb), &b,
	"signal::response", G_CALLBACK (response_cb), &b,
	NULL);

    /*
     * contents: headline, separator, wizard-specific part
     */

    /* headline */
    {
      GtkWidget *w, *b = gtk_hbox_new (0, 0);
      gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), b, FALSE, FALSE, 2);
      gtk_box_pack_start (GTK_BOX (b),
			  gtk_image_new_from_stock (GXINE_LOGO, icon_size_logo),
			  FALSE, FALSE, 2);
      w = gtk_label_new (_("<span face='serif' size='xx-large' weight='bold'>Welcome!</span>"));
      gtk_label_set_use_markup (GTK_LABEL (w), TRUE);
      gtk_box_pack_start (GTK_BOX (b), w, FALSE, FALSE, 2);
    }

    gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox),
			gtk_hseparator_new (), FALSE, FALSE, 5);

    window_show (dlg, NULL);

    state = -1;
    while (1)
    {
      GtkWidget *content = gtk_vbox_new (0, 0);
      gtk_box_pack_start_defaults (GTK_BOX (GTK_DIALOG (dlg)->vbox), content);

      if (wizards[++state].create)
      {
        if (wizards[state].create (dlg, content))
	  goto next;
      }
      else
      {
	gtk_dialog_set_response_sensitive (GTK_DIALOG (dlg), GTK_RESPONSE_ACCEPT, FALSE);
	add_heading (content, _("Setup completed."));
      }

      gtk_widget_show_all (content);
      gtk_main ();

      if (b == RESPONSE_CLOSE)
        break;

      if (wizards[state].action)
        wizards[state].action ();

      next:
      gtk_container_remove (GTK_CONTAINER (GTK_DIALOG (dlg)->vbox), content);
    }

    gtk_widget_destroy (dlg);
    dlg = NULL;
  }
}

static JSBool js_run_wizards (JSContext *cx, JSObject *obj, uintN argc,
			      jsval *argv, jsval *rval)
{
  /* se_t *se = (se_t *) JS_GetContextPrivate(cx); */
  se_log_fncall_checkinit ("run_wizards");
  run_wizards (TRUE);
  return JS_TRUE;
}

void wizards_init (void)
{
  se_defun (gse, NULL, "run_wizards", js_run_wizards, 0, 0,
	    SE_GROUP_HIDDEN, NULL, NULL);
}
